//
// Created by Japhy on 2017-9-1.
//
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include "jnipcsc.h"
#include "libpcsc.h"

/*
 * Class:     lc_com_pcsc_LibPcsc
 * Method:    native_init
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_lc_com_pcsc_LibPcsc_native_1init
        (JNIEnv *, jclass){
    Init();
    return 0;
}

/*
 * Class:     lc_com_pcsc_LibPcsc
 * Method:    native_slot
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_lc_com_pcsc_LibPcsc_native_1slot
        (JNIEnv *, jclass, jint slot)
{
    return SetSlot(slot);
}

/*
 * Class:     lc_com_pcsc_LibPcsc
 * Method:    native_poweron
 * Signature: (Ljava/lang/String;Llc/com/pcsc/DataUnit;)I
 */
JNIEXPORT jint JNICALL Java_lc_com_pcsc_LibPcsc_native_1poweron
        (JNIEnv *env, jclass clazz, jstring name, jobject atr)
{
    jclass atr_class = env->GetObjectClass(atr);
    jfieldID jfield_rlength = env->GetFieldID(atr_class, "length", "I");
    unsigned char atrBuff[512] = {0};
    size_t atrLen = 0;
    jint ret = PowerOn("", atrBuff, &atrLen);
    if(ret == 0){
        jfieldID jfield_rdata = env->GetFieldID(atr_class, "data", "[B");
        jbyteArray atr_array = (jbyteArray)env->GetObjectField(atr, jfield_rdata);

        env->SetIntField(atr, jfield_rlength, atrLen);
        env->SetByteArrayRegion(atr_array, 0, atrLen, (jbyte*)atrBuff);
    }
    return ret;
}

/*
 * Class:     lc_com_pcsc_LibPcsc
 * Method:    native_apdu
 * Signature: (Llc/com/pcsc/LibPcsc/DataUnit;Llc/com/pcsc/LibPcsc/DataUnit;)I
 */
JNIEXPORT jint JNICALL Java_lc_com_pcsc_LibPcsc_native_1apdu
        (JNIEnv *env, jclass clazz, jobject cobj, jobject robj){
    jclass capdu_class = env->GetObjectClass(cobj);
    jfieldID jfield_data = env->GetFieldID(capdu_class, "data", "[B");
    jbyteArray capdu_array = (jbyteArray)env->GetObjectField(cobj, jfield_data);
    jbyte* capdu = env->GetByteArrayElements(capdu_array, NULL);

    jfieldID jfield_length = env->GetFieldID(capdu_class, "length", "I");
    jint clen = env->GetIntField(cobj, jfield_length);

    jclass rapdu_class = env->GetObjectClass(robj);
    jfieldID jfield_rdata = env->GetFieldID(rapdu_class, "data", "[B");
    jbyteArray rapdu_array = (jbyteArray)env->GetObjectField(robj, jfield_rdata);
//    jbyte* rapdu = env->GetByteArrayElements(rapdu_array, NULL);
//
    jfieldID jfield_rlength = env->GetFieldID(rapdu_class, "length", "I");
    uint8_t rapdu[2048];
    uint32_t rlen;

    jint ret = Apdu((uint8_t*)capdu, (size_t)clen, rapdu, (size_t*)&rlen);
    if(ret == 0){
        env->SetIntField(robj, jfield_rlength, rlen);
        env->SetByteArrayRegion(rapdu_array, 0, rlen, (jbyte*)rapdu);
    }
    env->ReleaseByteArrayElements(capdu_array, capdu, 0);
    return ret;
}


// java中的jstring, 转化为c的一个字符数组
char*  Jstring2CStr(JNIEnv*   env,   jstring   jstr)
{
    char*   rtn   =   NULL;
    jclass   clsstring   =   env->FindClass("java/lang/String");
    jstring   strencode   =  env->NewStringUTF("UTF-8");
    jmethodID   mid   =   env->GetMethodID(clsstring,   "getBytes",   "(Ljava/lang/String;)[B");
    jbyteArray   barr=   (jbyteArray)env->CallObjectMethod(jstr,mid,strencode); // String .getByte("GB2312");
    jsize   alen   =   env->GetArrayLength(barr);
    jbyte*   ba   =   env->GetByteArrayElements(barr,JNI_FALSE);
    if(alen   >   0)
    {
        rtn   =   (char*)malloc(alen+1);         //new   char[alen+1]; "\0"
        memcpy(rtn,ba,alen);
        rtn[alen]=0;
    }
    env->ReleaseByteArrayElements(barr,ba,0);  //释放内存

    return rtn;
}

/*
 * Class:     lc_com_pcsc_LibPcsc
 * Method:    native_apdu_ascii
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_lc_com_pcsc_LibPcsc_native_1apdu_1ascii
        (JNIEnv *env, jclass clazz, jstring jstr){
    const char* capdu = Jstring2CStr(env, jstr);
    char rapdu[2048] = {0};
    int ret = ApduAscii(capdu, rapdu);
    if(ret){
        rapdu[0] = 0;
    }
    return env->NewStringUTF(rapdu);
}

/*
 * Class:     lc_com_pcsc_LibPcsc
 * Method:    native_poweroff
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_lc_com_pcsc_LibPcsc_native_1poweroff
        (JNIEnv *, jclass){
    PowerOff();
    return 0;
}

/*
 * Class:     lc_com_pcsc_LibPcsc
 * Method:    native_isCardPresent
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_lc_com_pcsc_LibPcsc_native_1isCardPresent
        (JNIEnv *, jclass, jstring){
    return IsCardPresent("");
}